/**
 * @author zlss
 * @date 2025/5/31
 * @description
 */
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

public class SudokuGame extends Application {
    private SudokuBoard sudokuBoard;
    private SudokuEngine engine;
    private GridPane boardGrid;
    private Label timerLabel;
    private Label errorLabel;
    private int errorCount = 0;
    private Timer timer;
    private int secondsElapsed = 0;
    private MediaPlayer successSound;
    private MediaPlayer errorSound;
    private MediaPlayer clickSound;

    @Override
    public void start(Stage primaryStage) {
        // 初始化媒体播放器
        try {
            successSound = new MediaPlayer(new Media(new File("success.mp3").toURI().toString()));
            errorSound = new MediaPlayer(new Media(new File("error.mp3").toURI().toString()));
            clickSound = new MediaPlayer(new Media(new File("click.mp3").toURI().toString()));
        } catch (Exception e) {
            System.out.println("无法加载音效文件: " + e.getMessage());
        }

        // 初始化游戏引擎和棋盘
        engine = new SudokuEngine();
        sudokuBoard = new SudokuBoard();

        // 创建UI组件
        BorderPane root = new BorderPane();
        root.setTop(createTitleBar());
        root.setCenter(createGameBoard());
        root.setRight(createControlPanel());

        // 设置CSS样式
        root.getStylesheets().add(getClass().getResource("sudoku.css").toExternalForm());

        // 开始新游戏
        startNewGame(Difficulty.EASY);

        // 设置场景和舞台
        Scene scene = new Scene(root, 800, 600);
        primaryStage.setTitle("数独游戏");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private HBox createTitleBar() {
        HBox titleBar = new HBox(10);
        titleBar.setPadding(new javafx.geometry.Insets(10));
        titleBar.setStyle("-fx-background-color: #4CAF50;");

        Label titleLabel = new Label("数独游戏");
        titleLabel.setFont(new Font(24));
        titleLabel.setTextFill(Color.WHITE);

        Button newGameButton = new Button("新游戏");
        newGameButton.setOnAction(e -> showDifficultyDialog());

        titleBar.getChildren().addAll(titleLabel, newGameButton);
        HBox.setHgrow(titleLabel, Priority.ALWAYS);

        return titleBar;
    }

    private GridPane createGameBoard() {
        boardGrid = new GridPane();
        boardGrid.setStyle("-fx-background-color: #f0f0f0; -fx-padding: 10;");

        // 创建9x9网格
        for (int row = 0; row < 9; row++) {
            for (int col = 0; col < 9; col++) {
                Cell cell = new Cell(row, col);
                cell.setPrefSize(50, 50);
                cell.setFont(new Font(20));
                cell.setAlignment(javafx.geometry.Pos.CENTER);
                cell.setOnMouseClicked(e -> selectCell(cell));
                cell.setOnKeyPressed(e -> handleKeyPress(cell, e.getCode()));

                // 添加边框样式
                String style = "-fx-border-color: black;";
                if (row % 3 == 0) style += "-fx-border-top-width: 2px;";
                if (col % 3 == 0) style += "-fx-border-left-width: 2px;";
                if (row == 8) style += "-fx-border-bottom-width: 2px;";
                if (col == 8) style += "-fx-border-right-width: 2px;";
                cell.setStyle(style);

                boardGrid.add(cell, col, row);
            }
        }

        return boardGrid;
    }

    private VBox createControlPanel() {
        VBox controlPanel = new VBox(10);
        controlPanel.setPadding(new javafx.geometry.Insets(10));
        controlPanel.setStyle("-fx-background-color: #e0e0e0;");

        // 创建数字键盘
        GridPane numPad = new GridPane();
        numPad.setHgap(5);
        numPad.setVgap(5);

        for (int i = 1; i <= 9; i++) {
            Button numButton = new Button(String.valueOf(i));
            numButton.setPrefSize(40, 40);
            final int number = i;
            numButton.setOnAction(e -> enterNumber(number));
            numPad.add(numButton, (i-1) % 3, (i-1) / 3);
        }

        // 创建功能按钮
        Button hintButton = new Button("提示");
        hintButton.setOnAction(e -> getHint());

        Button resetButton = new Button("重置");
        resetButton.setOnAction(e -> resetGame());

        Button checkButton = new Button("检查");
        checkButton.setOnAction(e -> checkSolution());

        // 创建计时器和错误计数器
        timerLabel = new Label("时间: 00:00");
        errorLabel = new Label("错误: 0");

        controlPanel.getChildren().addAll(
                new Label("控制面板"),
                numPad,
                hintButton,
                resetButton,
                checkButton,
                timerLabel,
                errorLabel
        );

        return controlPanel;
    }

    private void showDifficultyDialog() {
        javafx.scene.control.Alert alert = new javafx.scene.control.Alert(javafx.scene.control.Alert.AlertType.CONFIRMATION);
        alert.setTitle("选择难度");
        alert.setHeaderText("请选择游戏难度");

        javafx.scene.control.ChoiceDialog<Difficulty> dialog = new javafx.scene.control.ChoiceDialog<>(
                Difficulty.EASY, Difficulty.values());
        dialog.setTitle("选择难度");
        dialog.setHeaderText("请选择游戏难度");
        dialog.setContentText("难度:");

        dialog.showAndWait().ifPresent(difficulty -> startNewGame(difficulty));
    }

    private void startNewGame(Difficulty difficulty) {
        // 停止当前计时器
        if (timer != null) {
            timer.cancel();
        }

        // 重置错误计数
        errorCount = 0;
        errorLabel.setText("错误: 0");

        // 生成新的数独谜题
        engine.generatePuzzle(difficulty);
        sudokuBoard.setBoard(engine.getPuzzle());

        // 更新UI
        updateBoardUI();

        // 开始计时
        secondsElapsed = 0;
        updateTimerDisplay();
        timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                javafx.application.Platform.runLater(() -> {
                    secondsElapsed++;
                    updateTimerDisplay();
                });
            }
        }, 1000, 1000);
    }

    private void updateBoardUI() {
        for (int row = 0; row < 9; row++) {
            for (int col = 0; col < 9; col++) {
                Cell cell = (Cell) boardGrid.getChildren().get(row * 9 + col);
                int value = sudokuBoard.getValue(row, col);

                if (value == 0) {
                    cell.setText("");
                    cell.setEditable(true);
                } else {
                    cell.setText(String.valueOf(value));
                    cell.setEditable(!sudokuBoard.isEditable(row, col));
                }

                // 重置样式
                cell.setStyle(cell.getStyle().replaceAll("-fx-background-color:[^;]+;", ""));
                cell.setStyle(cell.getStyle().replaceAll("-fx-text-fill:[^;]+;", ""));
            }
        }
    }

    private void updateTimerDisplay() {
        int minutes = secondsElapsed / 60;
        int seconds = secondsElapsed % 60;
        timerLabel.setText(String.format("时间: %02d:%02d", minutes, seconds));
    }

    private Cell selectedCell;

    private void selectCell(Cell cell) {
        // 取消之前选中的单元格
        if (selectedCell != null) {
            selectedCell.setStyle(selectedCell.getStyle().replaceAll("-fx-background-color:[^;]+;", ""));
        }

        // 选中新单元格
        selectedCell = cell;
        cell.setStyle(cell.getStyle() + "-fx-background-color: #aaffaa;");
        cell.requestFocus();
    }

    private void handleKeyPress(Cell cell, javafx.scene.input.KeyCode code) {
        if (!cell.isEditable()) return;

        if (code.isDigitKey() && code.ordinal() >= javafx.scene.input.KeyCode.DIGIT1.ordinal() &&
                code.ordinal() <= javafx.scene.input.KeyCode.DIGIT9.ordinal()) {
            int number = code.ordinal() - javafx.scene.input.KeyCode.DIGIT1.ordinal() + 1;
            enterNumber(number);
        } else if (code == javafx.scene.input.KeyCode.BACK_SPACE || code == javafx.scene.input.KeyCode.DELETE) {
            clearCell(cell);
        }
    }

    private void enterNumber(int number) {
        if (selectedCell == null || !selectedCell.isEditable()) return;

        int row = selectedCell.getRow();
        int col = selectedCell.getCol();

        // 检查是否有冲突
        if (sudokuBoard.isValidMove(row, col, number)) {
            sudokuBoard.setValue(row, col, number);
            selectedCell.setText(String.valueOf(number));
            selectedCell.setStyle(selectedCell.getStyle().replaceAll("-fx-text-fill:[^;]+;", "") + "-fx-text-fill: blue;");

            // 播放点击音效
            if (clickSound != null) {
                clickSound.stop();
                clickSound.play();
            }

            // 检查是否完成
            if (sudokuBoard.isComplete()) {
                checkSolution();
            }
        } else {
            // 增加错误计数
            errorCount++;
            errorLabel.setText("错误: " + errorCount);

            // 播放错误音效
            if (errorSound != null) {
                errorSound.stop();
                errorSound.play();
            }

            // 显示冲突的单元格
            highlightConflicts(row, col, number);

            // 添加震动效果
            shakeCell(selectedCell);
        }
    }

    private void clearCell(Cell cell) {
        if (!cell.isEditable()) return;

        int row = cell.getRow();
        int col = cell.getCol();

        sudokuBoard.setValue(row, col, 0);
        cell.setText("");
        cell.setStyle(cell.getStyle().replaceAll("-fx-text-fill:[^;]+;", ""));
    }

    private void highlightConflicts(int row, int col, int number) {
        // 检查行冲突
        for (int c = 0; c < 9; c++) {
            if (c != col && sudokuBoard.getValue(row, c) == number) {
                Cell conflictCell = (Cell) boardGrid.getChildren().get(row * 9 + c);
                conflictCell.setStyle(conflictCell.getStyle() + "-fx-border-color: red; -fx-border-width: 2px;");
            }
        }

        // 检查列冲突
        for (int r = 0; r < 9; r++) {
            if (r != row && sudokuBoard.getValue(r, col) == number) {
                Cell conflictCell = (Cell) boardGrid.getChildren().get(r * 9 + col);
                conflictCell.setStyle(conflictCell.getStyle() + "-fx-border-color: red; -fx-border-width: 2px;");
            }
        }

        // 检查3x3宫格冲突
        int boxRow = row / 3 * 3;
        int boxCol = col / 3 * 3;
        for (int r = boxRow; r < boxRow + 3; r++) {
            for (int c = boxCol; c < boxCol + 3; c++) {
                if ((r != row || c != col) && sudokuBoard.getValue(r, c) == number) {
                    Cell conflictCell = (Cell) boardGrid.getChildren().get(r * 9 + c);
                    conflictCell.setStyle(conflictCell.getStyle() + "-fx-border-color: red; -fx-border-width: 2px;");
                }
            }
        }

        // 清除高亮效果（2秒后）
        javafx.application.Platform.runLater(() -> {
            javafx.animation.PauseTransition pause = new javafx.animation.PauseTransition(javafx.util.Duration.seconds(2));
            pause.setOnFinished(e -> {
                for (int r = 0; r < 9; r++) {
                    for (int c = 0; c < 9; c++) {
                        Cell cell = (Cell) boardGrid.getChildren().get(r * 9 + c);
                        cell.setStyle(cell.getStyle().replaceAll("-fx-border-color: red; -fx-border-width: 2px;", ""));
                    }
                }
            });
            pause.play();
        });
    }

    private void shakeCell(Cell cell) {
        javafx.animation.TranslateTransition tt = new javafx.animation.TranslateTransition(
                javafx.util.Duration.millis(50), cell);
        tt.setByX(5);
        tt.setCycleCount(4);
        tt.setAutoReverse(true);
        tt.play();
    }

    private void getHint() {
        if (sudokuBoard.isComplete()) return;

        // 获取一个提示
        int[] hint = engine.getHint(sudokuBoard);
        if (hint != null) {
            int row = hint[0];
            int col = hint[1];
            int number = hint[2];

            // 自动填充
            sudokuBoard.setValue(row, col, number);
            Cell cell = (Cell) boardGrid.getChildren().get(row * 9 + col);
            cell.setText(String.valueOf(number));
            cell.setStyle(cell.getStyle().replaceAll("-fx-text-fill:[^;]+;", "") + "-fx-text-fill: green;");

            // 选择这个单元格
            selectCell(cell);
        }
    }

    private void resetGame() {
        sudokuBoard.setBoard(engine.getPuzzle());
        updateBoardUI();
        errorCount = 0;
        errorLabel.setText("错误: 0");
    }

    private void checkSolution() {
        if (sudokuBoard.isComplete() && sudokuBoard.isValid()) {
            // 停止计时器
            if (timer != null) {
                timer.cancel();
            }

            // 播放成功音效
            if (successSound != null) {
                successSound.stop();
                successSound.play();
            }

            // 显示庆祝动画
            showCelebrationAnimation();

            // 显示成功对话框
            javafx.scene.control.Alert alert = new javafx.scene.control.Alert(javafx.scene.control.Alert.AlertType.INFORMATION);
            alert.setTitle("恭喜！");
            alert.setHeaderText("你完成了数独谜题！");
            int minutes = secondsElapsed / 60;
            int seconds = secondsElapsed % 60;
            alert.setContentText(String.format("用时: %02d:%02d\n错误次数: %d", minutes, seconds, errorCount));
            alert.showAndWait();
        } else {
            // 显示错误提示
            javafx.scene.control.Alert alert = new javafx.scene.control.Alert(javafx.scene.control.Alert.AlertType.WARNING);
            alert.setTitle("未完成");
            alert.setHeaderText("数独谜题尚未完成或存在错误");
            alert.setContentText("请检查你的答案并重试");
            alert.showAndWait();
        }
    }

    private void showCelebrationAnimation() {
        javafx.scene.layout.Pane root = new javafx.scene.layout.Pane();
        javafx.stage.Stage popupStage = new javafx.stage.Stage();
        popupStage.initOwner(boardGrid.getScene().getWindow());
        popupStage.initStyle(javafx.stage.StageStyle.TRANSPARENT);

        javafx.scene.Scene scene = new javafx.scene.Scene(root, boardGrid.getWidth(), boardGrid.getHeight());
        scene.setFill(javafx.scene.paint.Color.TRANSPARENT);
        popupStage.setScene(scene);

        // 创建烟花粒子
        for (int i = 0; i < 50; i++) {
            javafx.scene.shape.Circle circle = new javafx.scene.shape.Circle(
                    Math.random() * boardGrid.getWidth(),
                    Math.random() * boardGrid.getHeight(),
                    3 + Math.random() * 7,
                    javafx.scene.paint.Color.color(
                            Math.random(), Math.random(), Math.random(), 0.7)
            );

            root.getChildren().add(circle);

            javafx.animation.TranslateTransition tt = new javafx.animation.TranslateTransition(
                    javafx.util.Duration.seconds(1 + Math.random() * 2), circle);
            tt.setByY(-100 - Math.random() * 200);
            tt.setCycleCount(1);

            javafx.animation.FadeTransition ft = new javafx.animation.FadeTransition(
                    javafx.util.Duration.seconds(1 + Math.random() * 2), circle);
            ft.setFromValue(1.0);
            ft.setToValue(0.0);
            ft.setCycleCount(1);

            javafx.animation.ParallelTransition pt = new javafx.animation.ParallelTransition(tt, ft);
            pt.play();
        }

        popupStage.show();

        // 2秒后关闭动画
        javafx.application.Platform.runLater(() -> {
            javafx.animation.PauseTransition pause = new javafx.animation.PauseTransition(javafx.util.Duration.seconds(2));
            pause.setOnFinished(e -> popupStage.close());
            pause.play();
        });
    }

    public static void main(String[] args) {
        launch(args);
    }
}

